package com.pro.common.modules.service.dependencies.service;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pro.common.api.intf.IPayFeignClient;
import com.pro.common.api.intf.IUserDetailFeignClient;
import com.pro.common.api.model.ILoginInfo;
import com.pro.common.api.model.LoginInfo;
import com.pro.common.api.model.auth.IUserOrderClass;
import com.pro.common.api.model.request.pay.*;
import com.pro.common.modules.service.dependencies.model.request.IOrderRequest;
import com.pro.framework.api.util.AssertUtil;
import com.pro.framework.api.util.NumUtils;
import com.pro.framework.mybatisplus.BaseService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

public abstract class BaseOrderPayService<T extends IUserOrderClass, REQ extends IOrderRequest> {

    @Autowired(required = false)
    private IPayFeignClient payFeignClient;
    @Autowired(required = false)
    private IUserDetailFeignClient userDetailFeignClient;

    /**
     * 业务编号
     */
    public abstract IEnumPaymentBizType getBizType();
    public abstract BaseService<?, T> getService();

    /**
     * 业务下单(并发起支付)
     */
    public OrderResponse<T> createOrder(ILoginInfo loginInfo, REQ req, String ip) {
        T order = getService().newInstance();
        order.setUsername(loginInfo.getUsername());
        order.setUserId(loginInfo.getId());
        order.setIsDemo(loginInfo.getIsDemo());
        // 1.创建业务订单
        this.createOrder(loginInfo, req, order);

        BigDecimal orderAmount = order.getOrderAmount();
        PaymentParams params = req.getPaymentParams();
        // 支付金额大于零,表示发起支付
        PaymentResponse response = null;
        if (NumUtils.gt0(orderAmount) && null != params && null != payFeignClient) {
            // 2.发起支付
            response = payFeignClient.payment(new PaymentRequest(
                    (LoginInfo) loginInfo,
                    // 订单构建支付相关参数
                    this.getPaymentParamsDTO(order, params),
                    this.getPaymentUserDetail(params.getUserDetailRequired(), order.getUserId()),
                    ip)
            );
        }
        return new OrderResponse<>(order, response);
    }

    /**
     * 业务下单
     */
    protected abstract void createOrder(ILoginInfo loginInfo, REQ req, T order);

    /**
     * 支付成功
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrderPayCallbackSuccess(BigDecimal payAmount, Long orderId) {
        this.createOrderPayCallbackSuccess(payAmount, getService().getById(orderId));
    }

    /**
     * 支付成功
     */
    protected abstract void createOrderPayCallbackSuccess(BigDecimal payAmount, T order);

    /**
     * 支付失败
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrderPayCallbackFail(Long orderId) {
    }

    /**
     * 发起支付参数
     */
    private PaymentParamsDTO getPaymentParamsDTO(T order, PaymentParams params) {

        PaymentParamsDTO paymentParamsDTO = new PaymentParamsDTO();
        paymentParamsDTO.setBizType(this.getBizType().name());
        paymentParamsDTO.setBizId(order.getId());
        paymentParamsDTO.setBizDesc(order.getUserRemark());
        paymentParamsDTO.setOrderAmount(order.getOrderAmount());
        paymentParamsDTO.setSubject(order.getOrderSubject());
        paymentParamsDTO.setOrderNo(order.getOrderNo());
        paymentParamsDTO.setReturnUrl(params.getReturnUrl());
        paymentParamsDTO.setPayChannelId(params.getPayChannelId());
        return paymentParamsDTO;
    }

    /**
     * 部分支付,需要查询用户信息(email等)
     */
    private PaymentUserDetail getPaymentUserDetail(Boolean userDetailRequired, Long userId) {
        PaymentUserDetail userDetail = null;
        if (null != userDetailRequired && userDetailRequired) {
            AssertUtil.notEmpty(userDetailFeignClient, "当前通道需要用户信息_必须依赖user_service");
            IPaymentUserDetail user = userDetailFeignClient.getById(userId);
            userDetail = new PaymentUserDetail();
            userDetail.setEmail(user.getEmail());
            userDetail.setPhone(user.getPhonePrefix());
            userDetail.setUsername(user.getUsername());
            userDetail.setCountry(user.getCountry());
        }
        return userDetail;
    }
}
